﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner.Enums;
using AIStudio.Wpf.DiagramDesigner.Models;

namespace AIStudio.Wpf.DiagramDesigner
{
    public abstract class LogicalGateItemViewModelBase : DesignerItemViewModelBase
    {
        public ICommand AddInputCommand
        {
            get; private set;
        }
        public ICommand AddOutputCommand
        {
            get; private set;
        }

        public virtual bool EnableAddInput
        {
            get;
        } = false;

        public virtual bool EnableAddOutput
        {
            get;
        } = false;

        public LogicalGateItemViewModelBase(LogicalType logicalType) : this(null, logicalType)
        {

        }

        public LogicalGateItemViewModelBase(IDiagramViewModel root, LogicalType logicalType) : base(root)
        {
            this.LogicalType = logicalType;
        }

        public LogicalGateItemViewModelBase(IDiagramViewModel root, SelectableItemBase designer) : base(root, designer)
        {

        }

        public LogicalGateItemViewModelBase(IDiagramViewModel root, SerializableItem serializableItem, string serializableType) : base(root, serializableItem, serializableType)
        {

        }

        public override SelectableItemBase GetSerializableObject()
        {
            return new LogicalGateDesignerItemBase(this);
        }

        public override void Init(IDiagramViewModel root, bool initNew)
        {
            ShowRotate = false;
            ShowArrow = false;
            AddInputCommand = new SimpleCommand(Command_Enable, para => ExecuteAddInput(para));
            AddOutputCommand = new SimpleCommand(Command_Enable, para => ExecuteAddOutput(para));
            BuildMenuOptions();

            base.Init(root, initNew);
        }

        protected override void InitNew()
        {
            ExecuteAddInput(null);
            ExecuteAddInput(null);
            ExecuteAddOutput(null);
        }

        private void BuildMenuOptions()
        {
            menuOptions = new ObservableCollection<CinchMenuItem>();
            if (EnableAddInput == true)
            {
                CinchMenuItem menuItem = new CinchMenuItem();
                menuItem.Text = "添加输入";
                menuItem.Command = AddInputCommand;
                menuItem.CommandParameter = menuItem;
                menuOptions.Add(menuItem);
            }
            if (EnableAddOutput == true)
            {
                CinchMenuItem menuItem = new CinchMenuItem();
                menuItem.Text = "添加输出";
                menuItem.Command = AddOutputCommand;
                menuItem.CommandParameter = menuItem;
                menuOptions.Add(menuItem);
            }
        }

        protected override void LoadDesignerItemViewModel(SelectableItemBase designerbase)
        {
            base.LoadDesignerItemViewModel(designerbase);

            if (designerbase is LogicalGateDesignerItemBase designer)
            {
                this.LogicalType = designer.LogicalType;
                this.OrderNumber = designer.OrderNumber;
                this.Value = designer.Value;
                this.IsEnabled = designer.IsEnabled;

                ClearConnectors();
                Input.Clear();
                Output.Clear();

                if (designer.LogicalConnectors != null)
                {
                    foreach (var connector in designer.LogicalConnectors)
                    {
                        LogicalConnectorInfo fullyCreatedConnectorInfo = new LogicalConnectorInfo(this.Root, this, connector);

                        if (fullyCreatedConnectorInfo.Orientation == ConnectorOrientation.Left)
                        {
                            Input.Add(Input.Count, fullyCreatedConnectorInfo);
                        }
                        else if (fullyCreatedConnectorInfo.Orientation == ConnectorOrientation.Right)
                        {
                            Output.Add(Output.Count, fullyCreatedConnectorInfo);
                        }
                        AddConnector(fullyCreatedConnectorInfo);
                    }
                }
            }
        }

        private int _orderNumber;
        public int OrderNumber
        {
            get
            {
                return _orderNumber;
            }
            set
            {
                SetProperty(ref _orderNumber, value);
            }
        }

        private bool _isEnabled;
        public bool IsEnabled
        {
            get
            {
                return _isEnabled;
            }
            set
            {
                SetProperty(ref _isEnabled, value);
            }
        }


        private double _value;
        public double Value
        {
            get
            {
                return _value;
            }
            set
            {
                SetProperty(ref _value, value);
            }
        }

        public LogicalType LogicalType
        {
            get; set;
        }


        public Dictionary<int, LogicalConnectorInfo> Input { get; set; } = new Dictionary<int, LogicalConnectorInfo>();
        public Dictionary<int, LogicalConnectorInfo> Output { get; set; } = new Dictionary<int, LogicalConnectorInfo>();

        public override void ClearConnectors()
        {
            Connectors.Clear();
            Input.Clear();
            Output.Clear();
        }

        public virtual LogicalConnectorInfo ExecuteAddInput(object parameter, int index = 0, string name = null)
        {
            if (Input.Values.Count >= 2)
            {
                this.ItemHeight = this.ItemHeight * (Input.Values.Count + 1) / Input.Values.Count;
            }
            LogicalConnectorInfo connector = new LogicalConnectorInfo(this, ConnectorOrientation.Left, true, false, ValueTypeInput.Count > index ? ValueTypeInput[index] : ValueTypeInput[0]);
            connector.XRatio = 0;
            connector.Name = name ?? $"Input{index}";
            Input.Add(Input.Count, connector);
            for (int i = 0; i < Input.Values.Count; i++)
            {
                Input[i].YRatio = (i + 1.0) / (Input.Values.Count + 1.0);
            }
            AddConnector(connector);

            return connector;
        }

        public virtual LogicalConnectorInfo ExecuteAddOutput(object parameter, int index = 0, string name = null)
        {
            LogicalConnectorInfo connector = new LogicalConnectorInfo(this, ConnectorOrientation.Right, true, false, ValueTypeOutput.Count > index ? ValueTypeOutput[index] : ValueTypeInput[0]);
            connector.XRatio = 1;
            connector.Name = name ?? $"Output{index}";
            Output.Add(Output.Count, connector);
            for (int i = 0; i < Output.Values.Count; i++)
            {
                Output[i].YRatio = (i + 1.0) / (Output.Values.Count + 1.0);
            }
            AddConnector(connector);

            return connector;
        }

        public virtual List<ConnectorValueType> ValueTypeInput
        {
            get
            {
                return new List<ConnectorValueType>() { ConnectorValueType.Real };
            }
        }

        public virtual List<ConnectorValueType> ValueTypeOutput
        {
            get
            {
                return new List<ConnectorValueType>() { ConnectorValueType.Real };
            }
        }

        public void Execute()
        {
            GetInput();
            CalculateOutput();
        }

        public virtual void GetInput()
        {
            foreach (var input in Input)
            {
                var connector = GetSourceItem(input.Value);
                if (connector == null)
                {
                    input.Value.ErrorCode = ConnectorErrorCode.None;
                    continue;
                }

                if (connector.SourceConnectorInfoFully?.DataItem is LogicalGateItemViewModelBase sourceItem)
                {
                    var output = (connector.SourceConnectorInfoFully as LogicalConnectorInfo);

                    if (EnableInputValue(connector, input.Value, output))
                    {
                        connector.ColorViewModel.LineColor.Color = output.ColorViewModel.FillColor.Color;
                        connector.ColorViewModel.FillColor.Color = output.ColorViewModel.FillColor.Color;                      
                        connector.AnimationViewModel.Color = output.ColorViewModel.FillColor.Color;

                        input.Value.ConnectorValue = output.ConnectorValue;
                        input.Value.ConnectorString = output.ConnectorString;
                        input.Value.ColorViewModel.FillColor.Color = connector.SourceConnectorInfoFully.ColorViewModel.FillColor.Color;
                        if (LogicalType == LogicalType.Output)
                        {
                            input.Value.ConnectorValueType = (connector.SourceConnectorInfoFully as LogicalConnectorInfo).ConnectorValueType;
                        }
                        else if (LogicalType == LogicalType.NOT)
                        {
                            input.Value.ConnectorValueType = ((connector.SourceConnectorInfoFully as LogicalConnectorInfo).ConnectorValueType == ConnectorValueType.Bool) ? ConnectorValueType.Bool : ConnectorValueType.Int;
                        }

                        sourceItem.ClearOutputValue(connector, output);
                    }
                    sourceItem.StartAnimation(output);
                }
            }
        }

        public virtual void CalculateOutput()
        {
            foreach (var output in Output)
            {
                if (output.Value.ErrorCode != ConnectorErrorCode.None)
                {
                    output.Value.ColorViewModel.FillColor.Color = Colors.DarkRed;
                }
                else if (output.Value.ConnectorValueType == ConnectorValueType.Bool)
                {
                    if (output.Value.ConnectorValue == 0)
                    {
                        output.Value.ColorViewModel.FillColor.Color = Colors.Red;
                        if (LogicalType == LogicalType.Output)
                        {
                            ColorViewModel.FillColor.Color = Colors.Red;
                        }
                    }
                    else
                    {
                        output.Value.ColorViewModel.FillColor.Color = Colors.Green;
                        if (LogicalType == LogicalType.Output)
                        {
                            ColorViewModel.FillColor.Color = Colors.Green;
                        }
                    }
                }
                else if (output.Value.ConnectorValueType <= ConnectorValueType.ValueType)
                {
                    output.Value.ColorViewModel.FillColor.Color = Colors.Green;
                }
            }
        }

        public virtual bool EnableInputValue(ConnectionViewModel connector, LogicalConnectorInfo input, LogicalConnectorInfo output)
        {
            if (!input.CanAttachTo(output))
            {
                input.ErrorCode = ConnectorErrorCode.ConnErr;
                input.ErrorMessage = "连接类型不匹配";
                input.ColorViewModel.FillColor.Color = Colors.DarkRed;
                return false;
            }

            return true;
        }

        public virtual void ClearOutputValue(ConnectionViewModel connector, LogicalConnectorInfo output)
        {

        }

        public virtual void StartAnimation(LogicalConnectorInfo output)
        {

        }

        protected ConnectionViewModel GetSourceItem(FullyCreatedConnectorInfo sinkConnector)
        {
            return Root?.Items.OfType<ConnectionViewModel>().FirstOrDefault(p => p.SinkConnectorInfo == sinkConnector);
        }

        protected ConnectionViewModel GetSinkItem(FullyCreatedConnectorInfo sourceConnector)
        {
            return Root?.Items.OfType<ConnectionViewModel>().FirstOrDefault(p => p.SourceConnectorInfoFully == sourceConnector);
        }
    }
}
